package com.ruoyi.data.opc.config;

import com.google.common.collect.ImmutableList;
import com.ruoyi.data.opc.config.Client;
import io.swagger.models.auth.In;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.Stack;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class OpcUAClientUtils {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final CompletableFuture<OpcUaClient> future = new CompletableFuture<>();

    /**
     * OPC UA的运行入口程序
     */
    public void opcUaRun(String url) {
        try {
            // 创建OPC UA客户端
            OpcUaClient opcUaClient = Client.createClient(url);
            // future执行完毕后，异步判断状态
            checkStatus(future, opcUaClient);

            try {
                // 获取OPC UA服务器的数据
//                readYieldData(opcUaClient);
//                run(opcUaClient, future);
                future.get(5, TimeUnit.SECONDS);
            } catch (Throwable t) {
                logger.error("OPC UA客户端运行错误: {}", t.getMessage(), t);
                future.completeExceptionally(t);
            }
        } catch (Throwable t) {
            logger.error("OPC UA客户端创建错误: {}", t.getMessage(), t);
            future.completeExceptionally(t);
        }
    }

    /**
     * 异步判断状态
     *
     * @param future
     * @param opcUaClient
     */
    public void checkStatus(CompletableFuture<OpcUaClient> future, OpcUaClient opcUaClient) {
        // future执行完毕后，异步判断状态
        future.whenCompleteAsync((c, ex) -> {
            if (ex != null) {
                logger.error("连接OPC UA服务错误: {}", ex.getMessage(), ex);
            }
            // 关闭OPC UA客户端
            try {
                opcUaClient.disconnect().get();
                Stack.releaseSharedResources();
            } catch (InterruptedException | ExecutionException e) {
                logger.error("OPC UA服务关闭错误: {}", e.getMessage(), e);
            }
        });
    }

    /**
     * 覆盖接口方法，建立和OPC UA的服务
     * @param client
     * @param future
     * @throws Exception
     */
    public void run(OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception {
        AtomicInteger result = new AtomicInteger();
        // 异步读取数据
        readTagData(client).thenAccept(values -> {
            DataValue nodeId_Tag1 = values.get(0);
            DataValue nodeId_Tag2 = values.get(1);

            int moldHoleNumber = Integer.parseInt(nodeId_Tag1.getValue().getValue().toString());
            int openModulus = Integer.parseInt(nodeId_Tag2.getValue().getValue().toString());
            result.set(moldHoleNumber * openModulus);
            future.complete(client);
        });
    }

    /**
     * 读取标签点的数据
     */
    private CompletableFuture<List<DataValue>> readTagData(OpcUaClient client){
        // 同步建立连接
        try {
            client.connect().get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        NodeId nodeId_Tag1 = new NodeId(2, "通道 1.设备 1.标记 1");
        NodeId nodeId_Tag2 = new NodeId(2, "通道 1.设备 1.标记 2");
//        NodeId nodeId_Tag1 = new NodeId(1, 123457);
//        NodeId nodeId_Tag2 = new NodeId(1, 123460);
        List<NodeId> nodeIds = ImmutableList.of(nodeId_Tag1, nodeId_Tag2);
        return client.readValues(0.0, TimestampsToReturn.Both, nodeIds);
    }

//    public static int readYieldData(OpcUaClient client) {
//        int result = 0;
//        try {
//            client.connect().get();
//            NodeId nodeId_Tag1 = new NodeId(2, "通道 1.设备 1.标记 1");
//            NodeId nodeId_Tag2 = new NodeId(2, "通道 1.设备 1.标记 2");
//            List<NodeId> nodeIds = ImmutableList.of(nodeId_Tag1, nodeId_Tag2);
//            CompletableFuture<List<DataValue>> future = client.readValues(0.0, TimestampsToReturn.Both, nodeIds);
//            List<DataValue> valueList = future.get();
//            DataValue value1 = valueList.get(0);
//            DataValue value2 = valueList.get(1);
//            int moldHoleNumber = Integer.parseInt(value1.getValue().getValue().toString()); //模穴数
//            System.out.println("模穴数" + moldHoleNumber);
//            int openModulus = Integer.parseInt(value2.getValue().getValue().toString()); //开模序号
//            System.out.println("开模序号" + openModulus);
//            result = moldHoleNumber * openModulus;
//            System.out.println("产量" + result);
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
////            client.disconnect(); //关闭连接
//        }
//        return result;
//    }
}
